/**
 * 此类用于线程池功能
 */

#ifndef FRTHREADPOOL_H
#define FRTHREADPOOL_H

#include <thread>
#include <future>
#include <mutex>
#include <atomic>
#include <condition_variable>
#include <functional>
#include <vector>
#include <queue>
#include <algorithm>
#include <exception>
#include <utility>
#include <memory>

class FRThreadPool
{
private:
    // 线程池中的线程
    std::vector<std::thread> m_vecThreads;
    // 任务队列
    std::queue<std::function<void()>> m_queTask;

    // 保护任务队列
    std::mutex m_mtx;
    // 唤醒等待线程
    std::condition_variable m_cv;
    // 线程池启动标识
    std::atomic_bool m_isStart;

    // 线程池中线程的数量
    std::atomic_int16_t m_aPoolSize;
    // 获活跃线程的数量
    std::atomic_int16_t m_aActiveSize;

private:
    FRThreadPool(FRThreadPool &&) = delete;
    FRThreadPool &operator=(FRThreadPool &&) = delete;
    FRThreadPool(const FRThreadPool &) = delete;
    FRThreadPool &operator=(const FRThreadPool &) = delete;

public:
    FRThreadPool(const int16_t c_poolSize = 0);
    ~FRThreadPool();

    /**
     * @brief 向线程池中加入任务
     *
     * @param func
     * @param args
     * @return std::future<typename std::result_of<Func(Args...)>::type>
     */
    template <typename Func, typename... Args>
    std::future<typename std::result_of<Func(Args...)>::type> AddTask(Func &&func, Args &&...args);

    /**
     * @brief 启动线程池，不可连续多次启动一个线程池，可停止之后重启
     */
    void Start();

    /**
     * @brief 停止线程池
     */
    void Stop();

    /**
     * @brief 获得线程池中线程的数量
     *
     * @return int16_t
     */
    int16_t GetPoolSize() const;

    /**
     * @brief 调整线程池内线程的数量
     *
     * @param c_size
     */
    void ResizePool(const int16_t c_size);

    /**
     * @brief 获得活跃线程的数量
     *
     * @return int16_t
     */
    int16_t GetActiveSize() const;

    /**
     * @brief 获取任务列队中的任务的数量
     *
     * @return size_t
     */
    size_t GetDequeSize();

    /**
     * @brief 线程池是否启动
     * @return bool
     */
    bool IsStarted() const;
};

template <typename Func, typename... Args>
std::future<typename std::result_of<Func(Args...)>::type> FRThreadPool::AddTask(Func &&func, Args &&...args)
{
    // 获取该任务函数的返回类型
    typedef typename std::result_of<Func(Args...)>::type Func_ret_type;
    typedef std::packaged_task<Func_ret_type()> PackTask;

    // 将任务函数的参数原封不动的绑定到任务函数上，并任务封包
    std::shared_ptr<PackTask> spPackTask = std::make_shared<PackTask>(std::bind(std::forward<Func>(func), std::forward<Args>(args)...));
    // 获取任务封包的期望
    std::future<Func_ret_type> futureTask = spPackTask->get_future();
    {
        std::unique_lock<std::mutex> uLock(m_mtx);
        // 将任务加入任务队列
        m_queTask.emplace([spPackTask] { (*spPackTask)(); });
    }
    // 随机唤醒一条线程，执行任务队列中的任务
    m_cv.notify_one();

    return futureTask;
}

#endif // FRTHREADPOOL_H
